package org.zyj.io;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.LinkedList;

/**
 * Echo Server 2
 * 第二代 使用NIO:
 * 解决BIO的问题
 * ---
 * 优点:
 * 1. 已经突破了BIO的线程数量限制, 个位数的线程数就可以处理大量的连接
 * 2. 将建立连接和接收数据进行了区分
 * ---
 * 缺点:
 * 1. 建立连接的线程,和读取数据的线程, 都需要不停的轮询, 造成了大量的无效的操作, 浪费了大量CPU资源
 * 2. accept和read函数实际上会导致一次用户态到内核态的切换,也会浪费CPU
 */
public class SocketNIO {

    public static void main(String[] args) throws IOException {
        LinkedList<SocketChannel> clientList = new LinkedList<>();
        ServerSocketChannel ss = ServerSocketChannel.open();
        ss.bind(new InetSocketAddress(8080));
        ss.configureBlocking(false);//设置为非阻塞
        while (true) {
            //--------------------主线程----------------------------
            //这里的代码块, 实际上就是可以用一个线程轮询, 是否有新的连接进入
            SocketChannel client = ss.accept();//非阻塞, 可能返回null
            if (client != null) {
                //这里非空,就表示有新的连接进入
                client.configureBlocking(false);//设置为非阻塞
                clientList.add(client);
            }
            //--------------------主线程----------------------------

            //--------------------工作线程(池)----------------------------
            ByteBuffer buffer = ByteBuffer.allocateDirect(4096);
            //这里可以在其他线程池处理, 用一个或者几个线程疯狂遍历已经连接的客户端, 检查有没有新的数据进来
            //当然这里的代码就是在主线程中遍历,并读取数据,也是可以的, 就是效率肯定没有另外拉个线程读取数据来得高
            for (SocketChannel c : clientList) {//!!!!!!!!!!!!!!注意这里的轮询非常浪费CPU, 需要每个连接都去检查
                int num = c.read(buffer);//!!!!!!!!!!! 从客户端读取数据, 虽然这一步不是阻塞的, 但是这一步会发生用户态到内核态的转换
                if (num > 0) {//读得到就处理, 读不到就拉倒
                    buffer.flip();
                    byte[] aaa = new byte[buffer.limit()];
                    buffer.get(aaa);
                    String b = new String(aaa);
                    System.out.println(b);
                    buffer.clear();
                }
            }
            //--------------------工作线程(池)----------------------------


        }

    }
}
